/***
 * 测试完成RSA非对称加密和解密过程
 * 1.公钥和私钥实现字符化，可用字符形式保存
 * 2.加密后数据非对称
 * 尝试不同的编码记录byte[]
 */
package app.utils;

import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;

public class AsymmetricEncryption {

	public AsymmetricEncryption() {

	}

	/***
	 * 初始化key,返回的数组第一个是public，第二个是private
	 * 
	 * @param random
	 * @return
	 */
	public String[] initialKey(long random) {
		// 实例化Key

		KeyPairGenerator keyPairGenerator = null;
		try {
			keyPairGenerator = KeyPairGenerator.getInstance("RSA");
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		SecureRandom secureRandom = new SecureRandom();

		secureRandom.setSeed(random);

		keyPairGenerator.initialize(1024, secureRandom);

		// 获取一对钥匙
		KeyPair keyPair = keyPairGenerator.generateKeyPair();

		// 获得公钥
		Key publicKey = keyPair.getPublic();
		// 获得私钥
		Key privateKey = keyPair.getPrivate();

		String publicKeyString = StringUtil.byteArrayToHexString(publicKey.getEncoded());
		String privateKeyString = StringUtil.byteArrayToHexString(privateKey.getEncoded());

		String[] pkeys = { publicKeyString, privateKeyString };

		return pkeys;

	}

	/***
	 * 用公钥加密加密
	 * 
	 * @param plaintext
	 */
	public String encodeBypublickey(String publickey, String plaintext) {

		String ciphertxt = "";
		try {

			byte[] data = plaintext.getBytes();

			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			// 还原公钥
			X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(StringUtil.hexStringToByteArray(publickey));
			Key pukey = keyFactory.generatePublic(x509KeySpec);

			// 用公钥对数据加密
			Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
			cipher.init(Cipher.ENCRYPT_MODE, pukey);
			byte[] encodedData = cipher.doFinal(data);

			ciphertxt = StringUtil.byteArrayToHexString(encodedData);

		} catch (Exception e) {
			e.printStackTrace();
		}

		return ciphertxt;
	}

	/***
	 * 对大于117长度的字符加密
	 * 
	 * @param publickey
	 * @param longplaintext
	 * @return
	 */
	public String encodeLongtext(String publickey, String longplaintext) {
		String longcipher = "";
		int max_encode_length = 117;
		if (longplaintext.length() <= max_encode_length) {
			return encodeBypublickey(publickey, longplaintext);
		} else {
			// 需要加密的内容长度必须<117,max_encode_length
			int times = longplaintext.length() / max_encode_length;
			if (times * max_encode_length < longplaintext.length()) {
				times++;
			}
			for (int i = 0; i < times - 1; i++) {
				String substr = longplaintext.substring(i * max_encode_length, (i + 1) * max_encode_length);
				// System.out.println("substr" + i + ".length=" + substr.length()
				// + ",content=" + substr);
				longcipher += encodeBypublickey(publickey, substr) + ",";
			}

			String lastsubstr = longplaintext.substring((times - 1) * max_encode_length, longplaintext.length());
			// System.out.println("lastsubstr.length=" + lastsubstr.length()
			// + ",content=" + lastsubstr);
			longcipher += encodeBypublickey(publickey, lastsubstr);

			return longcipher;
		}
	}

	/***
	 * 对大于117长度的字符解密
	 * 
	 * @param publickey
	 * @param longencodestring
	 * @return
	 * @throws Exception
	 */
	public String decodeLongtext(String privatekey, String longcipher) throws Exception {
		String plaintext = "";
		String[] encodestrlist = longcipher.split(",");

		for (int i = 0; i < encodestrlist.length; i++) {
			plaintext += decodeByPrivatekey(privatekey, encodestrlist[i]);
		}
		return plaintext;
	}

	/***
	 * 用私钥解密
	 * 
	 * @param privatekey
	 * @param encodestring
	 * @throws Exception
	 */
	public String decodeByPrivatekey(String privatekey, String encodestring) throws Exception {
		byte[] decodedData = null;

		try {
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			// 还原私钥
			PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(StringUtil.hexStringToByteArray(privatekey));
			Key prkey = keyFactory.generatePrivate(pkcs8KeySpec);
			// 对数据解密
			Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
			cipher.init(Cipher.DECRYPT_MODE, prkey);

			byte[] encodedData = StringUtil.hexStringToByteArray(encodestring);

			decodedData = cipher.doFinal(encodedData);

		} catch (Exception e) {
			e.printStackTrace();
			throw e;
		}

		return new String(decodedData);
	}

	public static void main(String[] args) throws Exception {

		AsymmetricEncryption instance = new AsymmetricEncryption();
		/*
		 * //使用固定的密钥加密和解密 //String publicKeyString=
		 * "30819f300d06092a864886f70d010101050003818d003081890281810083d2e272e256e483313ad8ea4b8bacb81860bff238b03388acf98f664a50465f58ad22de7f864662f5ef60fbc0807f92a854173f9d69ce4371af41877e6caa124df0b020f7e13c49ba2bdabf43b6e7e81e9ac953e7c40f137db4bcb54b6fa180020354d97276d076ff80191485d926690c7d9551a246fea80583f6475afd5b610203010001";
		 * String privateKeyString=
		 * "30820275020100300d06092a864886f70d01010105000482025f3082025b0201000281810083d2e272e256e483313ad8ea4b8bacb81860bff238b03388acf98f664a50465f58ad22de7f864662f5ef60fbc0807f92a854173f9d69ce4371af41877e6caa124df0b020f7e13c49ba2bdabf43b6e7e81e9ac953e7c40f137db4bcb54b6fa180020354d97276d076ff80191485d926690c7d9551a246fea80583f6475afd5b6102030100010281807dc9955b9aaedf8e70437f08d2dd8d0a7df8943045f79cb526995c447754f251b9043ce9a33635a3e8996b29cf1ece9cdb12a2bc89309529b6294d964504dba30950085208449bf172987d12a5575272064379b99c8450d2d5a8a67095656451a38e3860ec2f2397d9c5023836f5078cae6179d61d1046ef0cc7bac069dc2f21024100d5369c964bcd4bcb3be5a8c0d472f1c1cb39950b68e85ed4076e8a1481f3bffb4bd2234ca7c5dc93e08260c0117b93ad3055557d154cecc64c931bbc67cbf98f0241009e470dffa651d16c52cee43c0f01f90f122756286036a4ca07a223fbf1e795f859727aaeab1eecd9aad7bf597e3bfa8aa581a751b8eec9ac31f4322dcae4840f02404fcb5b79082f71f1429e65b49d0dd39a92831f5ba0cc6e48edeb19b4291a5f3c1e192bead1534484f75df3f58dd570e43d1582a40867bca94e19342523b77bd3024065a1b6896be0a99ae6e95680821a80347f31a70f3208a473ddc6ed584012b6a7cbb7c8b313ca3dc7defdbe2ed6f1e884d295983ccf84f5168ed500cb8ab6855d0240352519c23d66cf06bb7867513f32eaebc14d2312c77d34f7605b068530f1137c71c3cbbf8a99421267e56a26b86082dc21380ae5c9fc1029d5b69cb333a326a4";
		 * String encodestring1=
		 * "43f6e3bafbc4556e6437d8a78a4abf20f92d1aa78edd4263b32cb815023605c10669629a9c75409da069016bbd19bcf8be17afb61aa1646e8f2a6f632f445099f7faea11f40679cdac6d1d3b737ab5826222fcca6daa9b45245310360d88d9e0d0c893e32fc601b6d5146c203ae091b3c796fb7f2cd1abb6e33c4d60f2c044ad";
		 * String encodestring2=
		 * "1976fa791d6b3fc0ab7f484c005bf2a031dd4250788973410d4005d7eac45e0ed6c30c5880be4b0d4b3c6716fa25df2400ff478f9342244ff87cf7fc1ebfeda4d8b3c8ad435db3484c5048bd4dc48283b031c684e9dd22ec1d557023570c0cee14ba38ffc6da91eae96dfa0d6333bbdebc1d49e552422b3727d95079167bf04c";
		 * String outputStr1 = instance.decodeByPrivatekey(privateKeyString,
		 * encodestring1);// 解密 String outputStr2 =
		 * instance.decodeByPrivatekey(privateKeyString, encodestring2);// 解密
		 * System.out.println("第1次解密: " + outputStr1); System.out.println("第2次解密: " +
		 * outputStr2);
		 * 
		 */

		// 演示生产密钥和加密，解密的过程

		long seek = System.currentTimeMillis();//
		String plaintext = "root";
		// 这时候打印出的只是一串数字而已
		System.out.println("TestEncrypt.TestEncrypt()随机种子：" + seek + "；需要加密的内容：" + plaintext);
		String[] keys = instance.initialKey(seek);
		String publicKeyString = keys[0];// public key
		String privateKeyString = keys[1];// private key
		System.out.println("publicKeyString.length=" + publicKeyString.length());
		System.out.println("publicKeyString=" + publicKeyString);
		System.out.println("privateKeyString.length=" + privateKeyString.length());
		System.out.println("privateKeyString=" + privateKeyString);
		String encodestring1 = instance.encodeBypublickey(publicKeyString, plaintext);// 加密
		String encodestring2 = instance.encodeBypublickey(publicKeyString, plaintext);// 加密
		System.out.println("第1次加密，长度：" + encodestring1.length() + "：" + encodestring1);
		System.out.println("第2次加密，长度：" + encodestring2.length() + "：" + encodestring2);
		String outputStr1 = instance.decodeByPrivatekey(privateKeyString, encodestring1);// 解密
		String outputStr2 = instance.decodeByPrivatekey(privateKeyString, encodestring2);// 解密
		System.out.println("第1次解密: " + outputStr1);
		System.out.println("第2次解密: " + outputStr2);
		// 测试对长文加密解密
		// String longplaintext = "1234567890abcdefghijklmnopqrstuvwxyz";
		String longplaintext = "1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz1234567890abcdefghijklmnopqrstuvwxyz";

		System.out.println("TestEncrypt.main()需要加密的内容长度必须<117");
		String encodelongtext = instance.encodeLongtext(publicKeyString, longplaintext);// 加密()
		System.out.println("TestEncrypt.main()长文加密：longplaintext.length=" + longplaintext.length() + "加密后长度="
				+ encodelongtext.length() + ",encodelongtext=" + encodelongtext);
		// 测试长文解密
		String longpt = instance.decodeLongtext(privateKeyString, encodelongtext);
		System.out.println("TestEncrypt.main()解密后的原文长度=" + longpt.length() + ",longpt=" + longpt);

	}

}
